#[cfg(feature = "rocksdb-backend")]
pub mod rocksdb_storage;
pub mod memory_storage;
pub mod distributed;
pub mod redis;

#[cfg(feature = "rocksdb-backend")]
pub use rocksdb_storage::*;
pub use memory_storage::*;
pub use distributed::*;
pub use redis::*;

// Re-export core types
pub use codegraph_core::{GraphStorage, Transaction, GraphQuery, QueryResult, Result, CodeGraphError, NodeId, EdgeId, CodeNode, CodeEdge};

use async_trait::async_trait;
use std::collections::HashMap;
use std::path::Path;
use thiserror::Error;

/// Storage-specific error types
#[derive(Error, Debug)]
pub enum StorageError {
    #[error("Database error: {0}")]
    Database(String),

    #[error("Serialization error: {0}")]
    Serialization(String),

    #[error("Not found: {0}")]
    NotFound(String),

    #[error("Connection error: {0}")]
    Connection(String),

    #[error("Configuration error: {0}")]
    Configuration(String),

    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),

    #[cfg(feature = "rocksdb-backend")]
    #[error("RocksDB error: {0}")]
    RocksDb(#[from] rocksdb::Error),
}

impl StorageError {
    pub fn database_error(msg: impl Into<String>) -> Self {
        Self::Database(msg.into())
    }

    pub fn serialization_error(msg: impl Into<String>) -> Self {
        Self::Serialization(msg.into())
    }

    pub fn not_found(msg: impl Into<String>) -> Self {
        Self::NotFound(msg.into())
    }

    pub fn connection_error(msg: impl Into<String>) -> Self {
        Self::Connection(msg.into())
    }

    pub fn configuration_error(msg: impl Into<String>) -> Self {
        Self::Configuration(msg.into())
    }
}

impl From<StorageError> for CodeGraphError {
    fn from(err: StorageError) -> Self {
        CodeGraphError::storage_error(err.to_string())
    }
}

/// Generic storage backend trait
#[async_trait]
pub trait StorageBackend: Send + Sync {
    /// Save a node to storage
    async fn save_node(&self, node: &dyn CodeNode) -> Result<()>;

    /// Save an edge to storage
    async fn save_edge(&self, edge: &dyn CodeEdge) -> Result<()>;

    /// Load a node from storage
    async fn load_node(&self, node_id: NodeId) -> Result<Option<Vec<u8>>>;

    /// Load an edge from storage
    async fn load_edge(&self, edge_id: EdgeId) -> Result<Option<Vec<u8>>>;

    /// Delete a node from storage
    async fn delete_node(&self, node_id: NodeId) -> Result<bool>;

    /// Delete an edge from storage
    async fn delete_edge(&self, edge_id: EdgeId) -> Result<bool>;

    /// List all nodes
    async fn list_nodes(&self) -> Result<Vec<NodeId>>;

    /// List all edges
    async fn list_edges(&self) -> Result<Vec<EdgeId>>;

    /// Find nodes by type
    async fn find_nodes_by_type(&self, node_type: &str) -> Result<Vec<NodeId>>;

    /// Find edges by type
    async fn find_edges_by_type(&self, edge_type: &str) -> Result<Vec<EdgeId>>;

    /// Find edges by source node
    async fn find_edges_by_source(&self, source_id: NodeId) -> Result<Vec<EdgeId>>;

    /// Find edges by target node
    async fn find_edges_by_target(&self, target_id: NodeId) -> Result<Vec<EdgeId>>;

    /// Execute a transaction
    async fn execute_transaction<F, R>(&self, transaction: F) -> Result<R>
    where
        F: FnOnce() -> Result<R> + Send,
        R: Send;

    /// Get storage statistics
    async fn get_stats(&self) -> Result<HashMap<String, String>>;

    /// Backup the database
    async fn backup<P: AsRef<Path> + Send>(&self, backup_path: P) -> Result<()>;

    /// Restore from backup
    async fn restore<P: AsRef<Path> + Send>(&self, backup_path: P) -> Result<()>;

    /// Compact the database
    async fn compact(&self) -> Result<()>;
}
